package br.ufpb.di.knowledgetv.sqtv.modules;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;

import br.ufpb.di.knowledgetv.algorithms.LetterPairSimilarity;
import br.ufpb.di.knowledgetv.sqtv.services.AbstractService;
import com.hp.hpl.jena.vocabulary.RDFS;
import org.apache.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Resource;

import br.ufpb.di.knowledgetv.sqtv.utils.Data;

@Component
public class SemanticEnrichmentModule implements SQTVModule, ApplicationContextAware {

    Logger logger = Logger.getLogger(SemanticEnrichmentModule.class);
    private ApplicationContext context;

	@SuppressWarnings("unchecked")
	@Override
	public Data execute(Data data) {
		List<Resource> resources = (List<Resource>) data.getData("ld_results");
        ConcurrentLinkedQueue<Model> models = new ConcurrentLinkedQueue<Model>();
        CountDownLatch latch = new CountDownLatch(resources.size());

		for (Resource r : resources) {
            try {
                Thread t = new Thread(new ReadModelThread(models,r,latch,(String) data.getData("keywords"), this.context));
                t.start();
            } catch (Exception e) {
                logger.error(e.getMessage());
            }
		}

        try {
            latch.await();
        } catch (InterruptedException e) {
            logger.error(e.getMessage());
        }

        ArrayList<Model> ald = new ArrayList<Model>();
        ald.addAll(models);
        data.addData("models", ald);

		return data;
	}

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }

    private class ReadModelThread implements Runnable {

        private ConcurrentLinkedQueue<Model> list;
        private Resource resource;
        private CountDownLatch latch;
        private String keywords;
        private ApplicationContext context;

        Logger logger = Logger.getLogger(ReadModelThread.class);

        public ReadModelThread(ConcurrentLinkedQueue<Model> list, Resource resource, CountDownLatch latch, String keywords, ApplicationContext context1) {
            this.list = list;
            this.resource = resource;
            this.latch = latch;
            this.keywords = keywords;
            this.context = context1;
        }

        @Override
        public void run() {
            String label = null;
            String beanName = null;
            try {
                label = this.resource.getProperty(RDFS.label).getString();
                if (LetterPairSimilarity.compareStrings(label, this.keywords) >= 0.6) {
                     beanName = this.resource.getProperty(RDFS.domain).getString();
                    AbstractService service = (AbstractService) this.context.getBean(beanName);
                    logger.info(String.format("[%s] - Iniciou thread - %s", beanName, label));
                    Model m = service.getModel(this.resource.getURI());
                    if(m == null) {
                        m = ModelFactory.assembleModelFrom(this.resource);
                    }
                    this.list.add(m);
                    logger.info(String.format("[%s] Finalizou thread - %s", beanName, label));
                }
            } catch (Exception e) {
                logger.error(String.format("[%s] %s", beanName, e.getMessage()));
            } finally {
                this.latch.countDown();
            }
        }
    }

}
